﻿#pragma once

#include "df_macro.h"
#include "BaseChar.h"
#include "basic_string_op.h"
#include "ErrCode.h"

#define DF_CATCH_ALL DF_CATCH_ALL_EXCEPTION(;)


#define DF_CATCH_ALL_EXCEPTION(_P) catch(df::Exception & seh)  \
	{ \
	df::CC Exception_Msg = seh.message_;\
	df::Exception::ExceptionLog(seh); Exception_Msg.size(); _P\
	} \
	catch (std::exception & ex) \
	{\
	df::String ExceStr; \
	ExceStr << tcc_("c++ exception:") << ex.what(); \
	df::CC Exception_Msg = ExceStr; \
	df::Exception::ExceptionLog(Exception_Msg); DF_BREAK_POINT;  _P\
	} \
	catch (...) \
	{ \
	df::CC Exception_Msg = tccr_(_T("Unknown C++ Exception") ); \
	df::Exception::ExceptionLog(Exception_Msg); DF_BREAK_POINT; _P\
	}

#ifdef WIN32
#	define DF_CATCH_SEGV 
#else
#	define DF_CATCH_SEGV
#	include <unistd.h>
#	include <signal.h>
#	include <setjmp.h>
#endif



namespace df
{

	using namespace sdf;


	class Exception
	{
	public:


		///异常信息
		String message_;
		///异常代码
		uint32_t code_;

#if _DEBUG || DF_LOG_FILE_LINE==1
		//文件名与行号
		df::CC fileLine_;

		Exception(const df::CC & msg, unsigned code, df::CC file = tcc_(""))
			: message_(msg.char_, msg.length_)
			, code_(code)
			, fileLine_(file)
		{}

		Exception(String && msg, unsigned code, df::CC file = tcc_(""))
			: message_(std::move(msg))
			, code_(code)
			, fileLine_(file)
		{}

#	define Throw_df(_msg) throw df::Exception(df::String()<<_msg,0,DF_FILE_LINE);
#	define ThrowErr(_msg,_err) throw df::Exception(df::String()<<_msg,_err,DF_FILE_LINE);
#	define ThrowLastErr(_msg) throw df::Exception(df::String()<<_msg,df::GetError(),DF_FILE_LINE);
#else

		Exception(const df::CC & msg, unsigned code)
			: message_(msg.char_, msg.length_)
			, code_(code)
		{}

		Exception(String && msg, unsigned code)
			: message_(std::move(msg))
			, code_(code)
		{}

#	define Throw_df(_msg) throw df::Exception(df::String()<<_msg,0);
#	define ThrowErr(_msg,_err) throw df::Exception(df::String()<<_msg,_err);
#	define ThrowLastErr(_msg) throw df::Exception(df::String()<<_msg,df::GetError());
#endif

		~Exception() throw()
		{}

#ifdef _MSC_VER
		///seh异常处理,将seh转换为c++异常
		static void MyTranslator(unsigned, EXCEPTION_POINTERS *info)
		{

			EXCEPTION_RECORD ExecR = *info->ExceptionRecord;

			String str;
			str << tcc_("Code:") << (void*)ExecR.ExceptionCode << tcc_(" Address:") << (void*)ExecR.ExceptionAddress;

			///访问违规
			if (ExecR.ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
			{
				str << tcc_("\r\n向非法内存地址:") << (void*)ExecR.ExceptionInformation[1]
					<< (ExecR.ExceptionInformation[0] ? tcc_("写入数据") : tcc_("读取数据"));
			}
			else if (ExecR.NumberParameters > 0)
			{
				str << tcc_("\r\nInformation:");
				for (DWORD i = 0; i < ExecR.NumberParameters; i++)
				{
					str << tcc_(" [") << i << tcc_("] ") << (void*)ExecR.ExceptionInformation[i];
				}
			}
			
			String lineInfo = str;
			lineInfo << tcc_("\r\n");
			df::Err::StackTrace(info->ContextRecord,lineInfo);
			df::WriteLog(lineInfo, false);

			throw Exception(std::move(str), 0);
		}

#else
		static void handlerSEGV(int sig_no, siginfo_t *pt_siginfo, void *p_ucontext)
		{
			
			/* Ensure we do not deadlock. Default of ALRM is to die.
			* (signal() and alarm() are signal-safe) */
			signal(sig_no, SIG_DFL);
			(void)alarm(30);

			std::string errInfo = "segmentation violation access invalid mem ";
			if(pt_siginfo)
				errInfo << pt_siginfo->si_addr<<"\r\n";



			df::Err::BackTrace(errInfo);
#ifdef __ANDROID__
			errInfo << "----\r\n";
			df::Err::print_call_link(errInfo, sig_no, pt_siginfo,p_ucontext);
#endif
			
			
			df::WriteLog(errInfo , false);
			sigset_t newmask;
			sigemptyset(&newmask);
			sigaddset(&newmask,SIGSEGV);
			sigprocmask(SIG_UNBLOCK,&newmask,NULL);

			if(pt_siginfo && pt_siginfo->si_addr == nullptr)
				throw Exception(tcc_("segmentation violation"), 0);


			// siglongjmp(getSIGJMP(), -1);
			/* Nope. (abort() is signal-safe) */
			signal(SIGABRT, SIG_DFL);
			abort();
		}

		static void handlerILL(int s)
		{
			throw Exception(tcc_("illegal instruction"), 0);
		}
		static void handlerFPE(int s)
		{
			throw Exception(tcc_("floating point exception"), 0);	
		}
		static sigjmp_buf & getSIGJMP()
		{
			static DF_THREAD_LOCAL_VAR sigjmp_buf env;
			return env;
		}
#endif




		///安装SEH异常处理
		inline static void Instal()
		{
#ifdef _MSC_VER
			_set_se_translator(MyTranslator);

#else

			struct sigaction act;
			//memset(&act, 0, sizeof(act));
			//act.sa_handler = handlerSEGV;
			act.sa_sigaction = handlerSEGV;
			sigemptyset(&act.sa_mask);
			//sigaddset(&act.sa_mask, SIG_UNBLOCK);
			act.sa_flags = SA_SIGINFO;
			sigaction(SIGSEGV, &act, 0);
			// 			signal(SIGSEGV, handlerSEGV);
			// 			signal(SIGILL, handlerSEGV);
			// 			signal(SIGFPE, handlerSEGV);
#endif
		}

		///异常日志
		inline static void ExceptionLog(Exception & seh);

		inline static void ExceptionLog(const df::CCa & str);

		inline static void ExceptionLog(const df::CCw & str);


		template<typename _CharT>
		inline static void ExceptionMsg(const _CharT * str)
		{
			//(void*)str;
#if ! DF_NO_SEH_MSG
			df::msg(str, DF_CHAR(_CharT, "异常"));
#endif
		}

	};

}

